package com.timepies.database;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.timepies.domain.Festivita;
import com.timepies.domain.Festivita.YearOutOfRangeException;
import com.timepies.domain.Intervallo;
import com.timepies.domain.MenuPies;
import com.timepies.domain.Pie;
import com.timepies.domain.Timepie;

//http://www.html.it/pag/49180/database-e-sqlite/
public class Service {

	// private method
	private static Service service;

	private Context context;

	private SQLiteDao dao;
	private MongoDao mdao;

	public Service(Context context) {
		this.context = (context != null) ? context : null;
		this.dao = (context != null) ? new SQLiteDao(context) : null;
		this.mdao = new MongoDao();
	}

	public static Service getInstance(Object obj) {
		if (service != null)
			return service;

		if (obj instanceof Context)
			service = new Service((Context) obj);

		if (obj instanceof Activity)
			service = new Service(((Activity) obj).getApplicationContext());

		return new Service(null);
	}

	// utility mongo
	public void saveAsyncTimepie(Object o) {
		mdao.saveAsync(o);
	}

	public List<Timepie> getList() {
		return mdao.getList();
	}

	public void deleteAsync(Object pie) {
		mdao.deleteAsync(pie);
	}

	public String myPhoneNumber() {
		try {
			TelephonyManager tMgr = (TelephonyManager) context
					.getSystemService(Context.TELEPHONY_SERVICE);
			return tMgr.getLine1Number();
		} catch (Exception e) {
			Log.e(toString(), e.getMessage());
		}
		return null;
	}

	// utility database

	public void save(String sub, String txt, String date) {
		dao.save(sub, txt, date);
	}

	public void update(String sub, String txt, String date, long id) {
		dao.update(sub, txt, date, id);
	}

	public boolean delete(long id) {
		return dao.delete(id);
	}

	public Cursor cursor() {
		return dao.cursor();
	}

	// utility frontend
	public MenuPies menuPies = MenuPies.TIMEPIES;

	public MenuPies getMenuPies() {
		return menuPies;
	}

	public void setMenuPies(MenuPies menuPies) {
		this.menuPies = menuPies;
	}

	// utility csv
	public List<Pie> getPies() throws Exception {
		InputStream dati = context.getAssets().open(Constants.DATI_CSV);
		List<Pie> listPie = new ArrayList<Pie>();
		InputStreamReader is = new InputStreamReader(dati);
		BufferedReader reader = new BufferedReader(is);
		reader.readLine();
		String pieLine;
		while ((pieLine = reader.readLine()) != null)
			listPie.add(new Pie(pieLine));
		return listPie;
	}

	public List<Pie> getPiesGroups(Activity a) throws Exception {
		List<Pie> listPie = getPies();
		Map<String, Pie> map = new HashMap<String, Pie>();
		Collections.shuffle(listPie, new Random(System.nanoTime()));
		List<Pie> subList = listPie.subList(0, 10);
		for (Pie pie : subList)
			map.put(pie.getCategoria(), pie);
		return new ArrayList<Pie>(map.values());
	}

	// utility database
	public List<Timepie> calcolaProssimeFeste() throws YearOutOfRangeException {
		Calendar c = new GregorianCalendar();
		int year = c.get(Calendar.YEAR);
		List<Timepie> list = getFeste(year);
		List<Timepie> nextList = getFeste(year + 1);
		list.addAll(nextList);
		return sort(list);

	}

	public List<Timepie> calcolaProssimiPonti() throws YearOutOfRangeException {
		Calendar c = new GregorianCalendar();
		int year = c.get(Calendar.YEAR);
		List<Timepie> list = getPonti(year);
		List<Timepie> nextList = getPonti(year + 1);
		list.addAll(nextList);
		return sort(list);
	}

	public String countFesteAndPonti() throws YearOutOfRangeException {
		Calendar c = new GregorianCalendar();
		int year = c.get(Calendar.YEAR);
		List<Timepie> list = getFeste(year);
		int lavorativi = list.size();
		int ponti = 0;
		for (Timepie festa : list) {
			Calendar x = new GregorianCalendar();
			x.setTime(festa.getRowDate());
			switch (x.get(Calendar.DAY_OF_WEEK)) {

			case Calendar.WEDNESDAY:
				ponti = ponti + 2;
				break;
			case Calendar.THURSDAY:
			case Calendar.TUESDAY:
				ponti++;
				break;
			case Calendar.SUNDAY:
			case Calendar.SATURDAY:
				lavorativi--;
				break;
			}
		}

		return year + "," + list.size() + "," + lavorativi + "," + ponti;
	}

	private List<Timepie> getFeste(int year) throws YearOutOfRangeException {
		List<Timepie> feste = new ArrayList<Timepie>();

		for (Festivita festa : Festivita.values())
			feste.add(new Timepie(festa, year));

		feste.add(new Timepie(Festivita.pasqua(year), "Pasqua"));
		feste.add(new Timepie(Festivita.pasquetta(year), "Pasquetta"));

		return feste;
	}

	private List<Timepie> getPonti(int year) throws YearOutOfRangeException {
		List<Timepie> ponti = new ArrayList<Timepie>();
		List<Timepie> feste = getFeste(year);

		for (Timepie festa : feste) {
			Calendar c = new GregorianCalendar();
			c.setTime(festa.getRowDate());
			String txt = festa.getOggetto();
			String frase = null;

			switch (c.get(Calendar.DAY_OF_WEEK)) {
			case Calendar.MONDAY:
				frase = "Settimana corta per " + txt + " dal " + add(c, 1)
						+ " al " + add(c, 3);
				festa.setOggetto(frase);
				ponti.add(festa);
				break;
			case Calendar.TUESDAY:
				frase = "Ponte per " + txt + " dal " + add(c, -1) + " al "
						+ add(c, +1);
				festa.setOggetto(frase);
				ponti.add(festa);
				break;
			case Calendar.WEDNESDAY:
				frase = "Ponte lungo per " + txt + " dal " + add(c, -2)
						+ " al " + add(c, 2) + " oppure dal " + add(c, 0)
						+ " al " + add(c, 2);
				festa.setOggetto(frase);
				ponti.add(festa);
				break;
			case Calendar.THURSDAY:
				frase = "Ponte per " + txt + " dal " + add(c, 0) + " al "
						+ add(c, +1);
				break;
			case Calendar.FRIDAY:
				frase = "Settimana corta per " + txt + " dal " + add(c, -4)
						+ " al " + add(c, +3);
				festa.setOggetto(frase);
				ponti.add(festa);
				break;
			}
		}
		return ponti;
	}

	private List<Timepie> sort(List<Timepie> feste) {
		Collections.sort(feste, new Comparator<Timepie>() {
			public int compare(Timepie m1, Timepie m2) {
				return m1.getRowDate().compareTo(m2.getRowDate());
			}
		});

		Calendar c = Calendar.getInstance();
		long oggi = c.getTime().getTime();
		c.add(Calendar.YEAR, 1);
		long oggiProssimoAnno = c.getTime().getTime();
		List<Timepie> festeFuture = new ArrayList<Timepie>();
		for (Timepie timepie : feste) {
			long current = timepie.getRowDate().getTime();
			if (oggi < current && current < oggiProssimoAnno)
				festeFuture.add(timepie);
		}

		return festeFuture;
	}

	private String add(Calendar calendar, int mod) {
		calendar.add(Calendar.DAY_OF_MONTH, mod);
		return Intervallo.date.format(calendar.getTime());
	}
}